package com.example.myhelloworld.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

import java.lang.Math;
//import java.security.MessageDigest;



/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */

public class Testhello implements EntryPoint {    
    String userName;
    String password;
    String hashString;
    boolean freshQuest = true;
    boolean weDontKnowIfTheUserExists = true;
    boolean questionAnswerFieldUp = false;
    /**
     * The message displayed to the user when the server cannot be reached or
     * returns an error.
     */
    private static final String SERVER_ERROR = "An error occurred while "
            + "attempting to contact the server. Please check your network "
            + "connection and try again.";


    /**
     * Create a remote service proxy to talk to the server-side Greeting service.
     */
    private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

    /**
     * This is the entry point method.
         */
    
    public void onModuleLoad() {
        
        /*   //resets databases with completely new users and exercises.
        greetingService.dropDataBaseExercises(new AsyncCallback<String>(){
            public void onFailure(Throwable caught) {            }
            public void onSuccess(String result) {}
        });
        greetingService.fillDataBaseExercises(new AsyncCallback<String>(){
            public void onFailure(Throwable caught) {            }
            public void onSuccess(String result) {}
        });
        */
        
        final Button sendButton = new Button("Send");
        final TextBox nameField = new TextBox();
        final DockPanel dPan = new DockPanel();
        final HTML east = new HTML("East");
        nameField.setText("math challenge");

        final VerticalPanel loginBox = new VerticalPanel();
        final HorizontalPanel usernameBox = new HorizontalPanel();
        final HorizontalPanel passwordBox = new HorizontalPanel();
        
        final HorizontalPanel secretQuestionBox = new HorizontalPanel();
        final HorizontalPanel secretAnswerBox   = new HorizontalPanel();
            
        secretQuestionBox.setVisible(false);
        secretAnswerBox.setVisible(false);
        
        final HorizontalPanel loginServicesBox = new HorizontalPanel();

		final TextBox userText = new TextBox();
		final PasswordTextBox passText = new PasswordTextBox();
		final TextBox quesText = new TextBox();
		final PasswordTextBox answText = new PasswordTextBox();
		userText.setText("");
		passText.setText("");
		quesText.setText("");
		answText.setText("");
		
		final Button loginButton = new Button("Login");

        loginBox.setSize("375px", "130px");
        loginBox.addStyleName("loginBox");

        loginBox.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
        loginBox.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);


        userText.addStyleName("userText");
        passText.addStyleName("passText");
        quesText.addStyleName("userText");
        answText.addStyleName("passText");

        
        usernameBox.setSpacing(5);
        usernameBox.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
        usernameBox.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
        usernameBox.add(new HTML("<font size=3>Enter username:    </font>"));
        usernameBox.add(userText);

        passwordBox.setSpacing(5);
        passwordBox.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
        passwordBox.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
        passwordBox.add(new HTML("<font size=3>Enter password:    </font>"));
        passwordBox.add(passText);


		secretQuestionBox.setSpacing(5);
		secretQuestionBox.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
		secretQuestionBox.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);		
		secretQuestionBox.add(new HTML("<font size=3>Enter your secret question</font>"));
		secretQuestionBox.add(quesText);
		
		
		secretAnswerBox.setSpacing(5);
		secretAnswerBox.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
		secretAnswerBox.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);		
		secretAnswerBox.add(new HTML("<font size=3>Enter your secret answer</font>"));
		
		secretAnswerBox.add(answText);
		
		
		loginButton.addStyleName("loginButton");
		loginBox.add(loginServicesBox);
		loginBox.add(usernameBox);
		loginBox.add(passwordBox);
		loginBox.add(secretQuestionBox);
		loginBox.add(secretAnswerBox);
		loginBox.add(loginButton);

        userText.setFocus(true);

        // We can add style names to widgets
        sendButton.addStyleName("sendButton");
        sendButton.setHeight("120px");
        dPan.setHorizontalAlignment(DockPanel.ALIGN_CENTER);
        dPan.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);


        east.addStyleName("eastField");
        east.setHeight("100%");

        HorizontalPanel topPanel = new HorizontalPanel();
        topPanel.addStyleName("topPanel");
        topPanel.setWidth("100%");
        topPanel.setHeight("100px");

        VerticalPanel textFrame = new VerticalPanel();
        textFrame.addStyleName("textFrame");
        textFrame.setHeight("100%");
        textFrame.setWidth("400px");

        topPanel.add(textFrame);

        //    dPan.setBorderWidth(1);
        //    dPan.setSpacing(3);
        dPan.setWidth("100%");
        dPan.setHeight("88%");
        dPan.addStyleName("dockpanelen");

        dPan.add(loginBox, DockPanel.NORTH);

        RootPanel.get().add(topPanel);
        RootPanel.get().add(dPan);

        // Focus the cursor on the name field when the app loads
//        nameField.setFocus(true);
//        nameField.selectAll();
//
//        // Create the popup dialog box
//        final DialogBox dialogBox = new DialogBox();
//        dialogBox.setText("Results so far:");
//        dialogBox.setAnimationEnabled(true);
//        final Button closeButton = new Button("Close");
//        // We can set the id of a widget by accessing its Element
//        closeButton.getElement().setId("closeButton");
//        final Label textToServerLabel = new Label();
//        final HTML serverResponseLabel = new HTML();
//        VerticalPanel dialogVPanel = new VerticalPanel();
//        dialogVPanel.addStyleName("dialogVPanel");
//
//        dialogVPanel.add(new HTML("<br><b>Math Server replies:</b>"));
//        dialogVPanel.add(serverResponseLabel);
//        dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
//        dialogVPanel.add(closeButton);
//        dialogBox.setWidget(dialogVPanel);


        // Add a handler to close the DialogBox

//		weDontKnowIfTheUserExists = true;

//        closeButton.addClickHandler(new ClickHandler() {
//            public void onClick(ClickEvent event) {
//                dialogBox.hide();
//                sendButton.setEnabled(true);
//                sendButton.setFocus(true);
//            }
//        });
        
        
        // clickhandler for loginbutton, controls basically everything until the user has logged in...
		loginButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event){
				//    		loginBox.setVisible(false);
				if (weDontKnowIfTheUserExists && (!questionAnswerFieldUp)){

					userName = userText.getText();
					password = passText.getText();
					int hashedPassword = password.hashCode(); 		//WARNING: a better hash-function should be used, this one is just for testing and proof of concept.
					//				hashString = Integer.toString(hashedPassword);
					hashString = Hasher.hash(password);
					try {		
						System.out.println("Trying the following hash against database: " + hashString+ "/" + password);
						greetingService.checkValidLogin(userName + "," + hashString, new AsyncCallback<String>(){

							public void onFailure(Throwable caught) {
								System.out.println("HUGE LOGIN-AUTH-FAIL" );
								onModuleLoad();
							}
							public void onSuccess(String result) {

								if (result.equals("true")){
									System.out.println("Success logging In, what to do now?!");
									loginBox.removeFromParent();
									getSidebarArgumentsForUser(dPan);
								} else if (result.equals("false")){
									greetingService.userNotInDatabase(userName, new AsyncCallback<Boolean>(){
										public void onFailure(Throwable caught) {}
										public void onSuccess(Boolean result) {
											if (result){
												//the user is not in the database, we are free to add him..
												loginBox.setSize("375px", "130px");
												secretQuestionBox.setVisible(true);
												secretAnswerBox.setVisible(true);
												weDontKnowIfTheUserExists = false;
												usernameBox.setVisible(false);
												passwordBox.setVisible(false);
												
											}else{
												//if the username typed in exists, but the password is wrong, we get here..
												System.out.println("Incorrect password!! Try Again!");
												
												weDontKnowIfTheUserExists = false;
												
												passText.setText("");
												answText.setText("");
												secretQuestionBox.setVisible(true);
												secretAnswerBox.setVisible(true);
												
												usernameBox.setVisible(false);
												passwordBox.setVisible(false);
												
												questionAnswerFieldUp = true;
												
												greetingService.getUserQuestion(userName, new AsyncCallback<String>(){
													public void onFailure(Throwable caught){}
													public void onSuccess(String question) {
														// here we get, when the user has tried logging in, a fails typing in the correct password
														quesText.setText(question);
														
													}
												});											
											}
										}});

								} else {
									System.out.println("Never supposed to get here, something fishy is going on..");
								}
							}});
					} catch (Exception e) {}
				} else if ((!weDontKnowIfTheUserExists) && (!questionAnswerFieldUp)){	//we get here if the user login has failed and the username tried does not exist in database, here we add field for creation of a user.
					String question = quesText.getText();
					String answer = answText.getText();
					String hashAnswer = Hasher.hash(answer);
					greetingService.adduser(userName, hashString, question, hashAnswer, new AsyncCallback<String>(){
						public void onFailure(Throwable caught) {}
						public void onSuccess(String result) {
							loginBox.setSize("375px", "130px");
							secretQuestionBox.setVisible(false);
					        secretAnswerBox.setVisible(false);
					        
					    	usernameBox.setVisible(true);
							passwordBox.setVisible(true);
					        
					        weDontKnowIfTheUserExists = true;							
							
						}});
				} else if (questionAnswerFieldUp){
					System.out.println("Checking if following is a valid answer : " + answText.getText());
					greetingService.checkValidAnswer(userName, Hasher.hash(answText.getText()), new AsyncCallback<String>(){

						public void onFailure(Throwable caught) {}
						public void onSuccess(String result) {
							if (!result.equals("false")){
								System.out.println("Success logging In!");
								loginBox.removeFromParent();
								hashString = result;
								
								getSidebarArgumentsForUser(dPan);
							}else{
								quesText.setText("");
								answText.setText("");
								secretQuestionBox.setVisible(false);
						        secretAnswerBox.setVisible(false);
						        usernameBox.setVisible(true);
								passwordBox.setVisible(true);
						        loginBox.setSize("375px", "130px");
							}
						}
					});			
					questionAnswerFieldUp = false;
				} else  {	
				}
			}
        });
  }

    
    public void getSidebarArgumentsForUser(DockPanel dopan){
        final DockPanel dPan = dopan;
        // pretend that this is a serverinterface that returns a list of suitable exercise descriptors depending the type of the user.
//        String[] args ={"plusMinusDivTimes:Plus","plusMinusDivTimes:Minus","plusMinusDivTimes:Times","plusMinusDivTimes:Div",
//                "sudoku:030090008905218000000340620100009203300410066098000070401083000000524801200060090", "TextExercise:Argumentdoesnotmatter","TestExercise:plusMinusDivTimes:Plus,sudoku:030090008905218000000340620100009203300410066098000070401083000000524801200060090"};
        AsyncCallback<String[]> callback;
        String args = "";
        greetingService.getSidebarList(userName + "," + hashString, new AsyncCallback<String>(){

            public void onFailure(Throwable caught) {
            }

            public void onSuccess(String result) {
        
                System.out.println("About to add lissteners to the following parameters: " + result);
        
                String sidebarLabels = result.split("@")[1];
                String sidebarContent = result.split("@")[0];
                
                SidebarMenu leftside = new SidebarMenu(sidebarLabels.split(","));

                dPan.add(leftside.getPanel(), DockPanel.WEST);
                dPan.setCellWidth(leftside.getPanel(), "240px");
                dPan.setCellHeight(leftside.getPanel(), "100%");
                Panel currentMidPanel = (new VerticalPanel());
                dPan.add(currentMidPanel, DockPanel.WEST);
                
                addListeners(leftside, dPan, sidebarContent.split("-"));
                
            }});  
    }

    /**
     * Creates Exercises and listerners to buttons in sidebarar that links to that listeners
     *
     * @param left the sidebar whose elements we want to add listeners for
     * @param doPan the DockPanel to add exercises to
     */
    public void addListeners(final SidebarMenu left, DockPanel doPan, String[] listofarguments){
        final DockPanel dapan = doPan;
        final String[] arg = listofarguments;
        final produceExercise exerciseCreater= new produceExercise(userName, greetingService);
        
        for (int i= 0;i<left.getNumberOfSidebarButtons();i++){
//            final ExerciseClass exercise = exerciseCreater.exerciseFromString(arg[i]);
            
            // final declared loop-variables... looks a bit too ugly.. but it 'works'
            final int index = i;
            
            left.GetListElement(i).addClickHandler(new ClickHandler(){
                public void onClick(ClickEvent event) {
                    String exerciseName = (left.optionList)[index].getText();
                    // TODO Auto-generated method stub
                    removeExercise(dapan);
                    System.out.println("Arg: " + arg[index]);
                    ExerciseClass exercise = exerciseCreater.exerciseFromString(arg[index]);
                    exercise.getProduceResultButton().addClickHandler((ClickHandler) new CorrectHandler(greetingService,exercise, exerciseName, userName + "," + hashString ));
                    dapan.add(exercise.getSelfPanel(),DockPanel.EAST);
                }
            });   
        }
    }
    
    /**
     * removeExercise removes the currently active exercise, known by its styleName. All exercises should have the name "ExerciseBasic" 
     *
     * @param dpan The DockPanel too look for exercises in.
     */
    public void removeExercise(DockPanel dpan){
        int count = dpan.getWidgetCount();
        for (int i=0;i<count;i++){
            Widget trial = dpan.getWidget(i);
//            System.out.println("Any difference? testString = \"" + teststring + "\" , trial.getStyleName() = \"" + trial.getStyleName()+ "\" Compare: (teststring == trial.getStyleName()) = " + (teststring == trial.getStyleName()));
            if (trial.getStyleName().contains("ExerciseBasic") || trial.getStyleName().contains("sudoku") || trial.getStyleName().contains("Exercise")){
                trial.removeFromParent();
            }
        }
    }
     
}

